/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package simhya.matheval;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

/**
 *
 * @author Luca
 */
public class SymbolArray {
    double[] values;
    ArrayList<String> names;
    int numberOfSymbols;
    HashMap<String,Integer> symbolLookupTable;

    
    public SymbolArray() {
        values = new double[16];
        names = new ArrayList(16);
        numberOfSymbols = 0;
        symbolLookupTable = new HashMap<String,Integer>();
    }

    private SymbolArray(int size) {
        values = new double[size];
        names = null;
        symbolLookupTable = null;
        numberOfSymbols = size;
    }

    /**
     * use to get a symbolarray for fast eval of dynamics functions.
     * @param size
     */
    public static SymbolArray getNewFastEvalSymbolArray(int size) {
        return new SymbolArray(size);
    }

    public int addSymbol(String name, double value) {
        if (this.symbolLookupTable.containsKey(name))
            throw new EvalException("Symbol " + name + " already defined");
        int id = this.numberOfSymbols;
        if (values.length == this.numberOfSymbols)
            this.values = Arrays.copyOf(values, 2*values.length);
        this.names.add(name);
        this.values[id] = value;
        this.symbolLookupTable.put(name, id);
        this.numberOfSymbols++;
        return id;
    }

    public String getName(int id) {
        if (id <0 || id >= this.numberOfSymbols)
            throw new EvalException("There is no symbol with id " + id);
        return names.get(id);
    }

    public ArrayList<String> getNameOfAllSymbols() {
        return (ArrayList<String>)names.clone();
    }

    public int getSymbolId(String name) {
        Integer id = this.symbolLookupTable.get(name);
        if (id == null)
            throw new EvalException("Variable " + name + " undefined.");
        return id;
    }


    public boolean isDefined(String name) {
         return  (this.symbolLookupTable.containsKey(name));
    }

    public double getValue(int id) {
        return this.values[id];
    }
    
    public void setValue(int id, double x) {
        this.values[id] = x;
    }

    public int getNumberOfSymbols() {
        return this.numberOfSymbols;
    }

    public boolean checkSymbolIndex(int id) {
        if (id <0 || id >= this.numberOfSymbols)
            return false;
        return true;
    }


    public void fixValueArray() {
        if (values == null)
            values = new double[this.numberOfSymbols];
        if (values.length != this.numberOfSymbols)
            values = Arrays.copyOf(values, numberOfSymbols);
    }


    public double[] getReferenceToValuesArray() {
        return this.values;
    }

    public double[] getCopyOfValuesArray() {
        return Arrays.copyOf(values, numberOfSymbols);
    }


    public void copyValues(SymbolArray array) {
        if (array.numberOfSymbols != this.numberOfSymbols)
            throw new EvalException("Number of symbols mismatch");
        this.values = Arrays.copyOf(array.values, numberOfSymbols);
    }

    public void setValuesReference(SymbolArray array) {
        if (array.numberOfSymbols != this.numberOfSymbols)
            throw new EvalException("Number of symbols mismatch");
        this.values = array.values;
    }

}
